package com.upup.cloud.insert.utils;

import com.google.gson.*;
import com.google.gson.internal.LinkedTreeMap;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.lang.reflect.Type;
import java.security.NoSuchAlgorithmException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
public class StrUtils {

    static Gson gson = new GsonBuilder()
            .registerTypeAdapter(
                    new TypeToken<TreeMap<String, Object>>() {
                    }.getType(),
                    new JsonDeserializer<TreeMap<String, Object>>() {
                        @Override
                        public TreeMap<String, Object> deserialize(
                                JsonElement json, Type typeOfT,
                                JsonDeserializationContext context) throws JsonParseException {

                            TreeMap<String, Object> treeMap = new TreeMap<>();
                            JsonObject jsonObject = json.getAsJsonObject();
                            Set<Map.Entry<String, JsonElement>> entrySet = jsonObject.entrySet();
                            for (Map.Entry<String, JsonElement> entry : entrySet) {
                                treeMap.put(entry.getKey(), entry.getValue());
                            }
                            return treeMap;
                        }
                    }).create();

    /**
     * 参数转json
     *
     * @param string
     * @return
     */
    public static String paramTojson(String string) {
        Map<String, String> stringMap = new HashMap<String, String>();
        String[] strs = string.split("&");
        for (String str : strs) {
            String[] sts = new String[]{"", ""};
            String[] st = str.split("=");
            if (st.length == 1) {
                sts[0] = st[0];
            } else {
                sts[0] = st[0];
                sts[1] = st[1];
            }
            stringMap.put(sts[0], sts[1]);
        }
        return gson.toJson(stringMap);
    }

    /**
     * bean转json
     *
     * @param string
     * @return
     */
    public static String beanTojson(Object string) {
        return gson.toJson(string);
    }

    /**
     * bean转参数
     *
     * @param object
     * @return
     */
    public static String beanToParam(Object object) {
        return jsonToParam(gson.toJson(object));
    }

    /**
     * json转参数
     *
     * @param string
     * @return
     */
    public static String jsonToParam(String string) {
        Map<String, String> map = gson.fromJson(string, Map.class);
        String str = "";
        for (Map.Entry<String, String> entry : map.entrySet()) {
            str += entry.getKey() + "=" + entry.getValue() + "&";
        }
        str = str.substring(0, str.length() - 1);
        return str;
    }

    /**
     * json转bean
     *
     * @param string
     * @return
     */
    public static Object jsonTobean(String string, Class<?> t) {
        return gson.fromJson(string, t);
    }

    /**
     * json字符串转list或者map
     *
     * @param json
     * @param typeToken
     * @return
     */
    public static <T> T fromJson(String json, TypeToken<T> typeToken) {
        Gson gson = new GsonBuilder().registerTypeAdapter(new TypeToken<Map<String, Object>>() {}.getType(), new MapTypeAdapter()).create();
    //MapTypeAdapter是继承了TypeAdapter类，并单独处理Map类型的反序列化。注意：目前只绑定了Map类型，其子类（HashMap）的处理没有变化。具体代码见本文最后或GitHub（发布后会给出地址）。
        return gson.fromJson(json, typeToken.getType());
    }
    public static class MapTypeAdapter extends TypeAdapter<Object> {

        @Override
        public Object read(JsonReader in) throws IOException {
            JsonToken token = in.peek();
            switch (token) {
                case BEGIN_ARRAY:
                    List<Object> list = new ArrayList<Object>();
                    in.beginArray();
                    while (in.hasNext()) {
                        list.add(read(in));
                    }
                    in.endArray();
                    return list;

                case BEGIN_OBJECT:
                    Map<String, Object> map = new LinkedTreeMap<String, Object>();
                    in.beginObject();
                    while (in.hasNext()) {
                        map.put(in.nextName(), read(in));
                    }
                    in.endObject();
                    return map;

                case STRING:
                    return in.nextString();

                case NUMBER:
                    /**
                     * 改写数字的处理逻辑，将数字值分为整型与浮点型。
                     */
                    double dbNum = in.nextDouble();

                    // 数字超过long的最大值，返回浮点类型
                    if (dbNum > Long.MAX_VALUE) {
                        return dbNum;
                    }

                    // 判断数字是否为整数值
                    long lngNum = (long) dbNum;
                    if (dbNum == lngNum) {
                        return lngNum;
                    } else {
                        return dbNum;
                    }

                case BOOLEAN:
                    return in.nextBoolean();

                case NULL:
                    in.nextNull();
                    return null;

                default:
                    throw new IllegalStateException();
            }
        }

        @Override
        public void write(JsonWriter out, Object value) throws IOException {
            // 序列化无需实现
        }

    }
    public static String readToString(String fileName) {
        String encoding = "UTF-8";
        File file = new File(fileName);
        Long filelength = file.length();
        byte[] filecontent = new byte[filelength.intValue()];
        try {
            FileInputStream in = new FileInputStream(file);
            in.read(filecontent);
            in.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            return new String(filecontent, encoding);
        } catch (UnsupportedEncodingException e) {
            System.err.println("The OS does not support " + encoding);
            e.printStackTrace();
            return null;
        }
    }


    /**
     * bean 转sql插入
     */
    public static String jsonToListSql(String json, String tb) {
        Type type = new TypeToken<List<Map<String, Object>>>() {
        }.getType();
        List<Map<String, Object>> list = gson.fromJson(json, type);
        String str = "INSERT INTO " + tb + " (";
        String sss = "";
        for (Map.Entry<String, Object> entry : list.get(0).entrySet()) {
            if (null != entry.getValue() && !entry.getValue().toString().equals("0.0")) {
                sss += "`" + entry.getKey() + "`,";
            }
        }
        sss = sss.substring(0, sss.length() - 1);
        str += sss;
        str += ") VALUES ";
        for (Map<String, Object> map : list) {
            str += "(";
            String bbb = "";
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                if (null != entry.getValue() && !entry.getValue().toString().equals("0.0")) {
                    bbb += "'" + entry.getValue() + "',";
                }
            }
            bbb = bbb.substring(0, bbb.length() - 1);
            str += bbb;
            str += "),";
        }
        str = str.substring(0, str.length() - 1);
        System.err.println(str);
        try {
            return new String(str.getBytes("UTF-8"), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * bean 转sql插入
     */
    public static String jsonToSql(String json, String tb) {
        Map<String, Object> map = gson.fromJson(json, Map.class);
        String str = "INSERT INTO " + tb + " (";
        String sss = "";
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (null != entry.getValue() && !entry.getValue().toString().equals("0.0")) {
                sss += "`" + entry.getKey() + "`,";
            }
        }
        sss = sss.substring(0, sss.length() - 1);
        str += sss;
        str += ") VALUES (";
        String bbb = "";
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (null != entry.getValue() && !entry.getValue().toString().equals("0.0")) {
                bbb += "'" + entry.getValue() + "',";
            }
        }
        bbb = bbb.substring(0, bbb.length() - 1);
        str += bbb;
        str += ")";
        try {
            return new String(str.getBytes("UTF-8"), "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return "";
    }

    public static String jsonToCreate(String json, String tb) {
        Map<String, Object> map = gson.fromJson(json, Map.class);
        String str = "CREATE TABLE `" + tb + "` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT,";
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            str += "`" + entry.getKey() + "` varchar(200) DEFAULT NULL,";
        }
        str += " PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;";
        return str;
    }


    /**
     * bean 转sql插入
     */
    public static String jsonToUpdateSql(String json, String tb, String where) {
        Map<String, Object> map = gson.fromJson(json, Map.class);
        String str = "UPDATE " + tb + " set ";
        String sss = "";
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (null != entry.getValue() && !entry.getValue().toString().equals("0.0")) {
                sss += "`" + entry.getKey().toString() + "`" + "='" + entry.getValue() + "',";
            }
        }
        sss = sss.substring(0, sss.length() - 1);
        str += sss;
        str += " where " + where;
//        System.err.println(str);
        return str;
    }


    public static String getRandom(int num) {
        String sources = "0123456789"; // 加上一些字母，就可以生成pc站的验证码了
        Random rand = new Random();
        StringBuffer flag = new StringBuffer();
        for (int j = 0; j < num; j++) {
            flag.append(sources.charAt(rand.nextInt(9)) + "");
        }
        return flag.toString();
    }

    public static String getRandomIp() {

        // ip范围
        int[][] range = {{607649792, 608174079}, // 36.56.0.0-36.63.255.255
                {1038614528, 1039007743}, // 61.232.0.0-61.237.255.255
                {1783627776, 1784676351}, // 106.80.0.0-106.95.255.255
                {2035023872, 2035154943}, // 121.76.0.0-121.77.255.255
                {2078801920, 2079064063}, // 123.232.0.0-123.235.255.255
                {-1950089216, -1948778497}, // 139.196.0.0-139.215.255.255
                {-1425539072, -1425014785}, // 171.8.0.0-171.15.255.255
                {-1236271104, -1235419137}, // 182.80.0.0-182.92.255.255
                {-770113536, -768606209}, // 210.25.0.0-210.47.255.255
                {-569376768, -564133889}, // 222.16.0.0-222.95.255.255
        };

        Random rdint = new Random();
        int index = rdint.nextInt(10);
        String ip = num2ip(range[index][0] + new Random().nextInt(range[index][1] - range[index][0]));
        return ip;
    }

    /*
     * 将十进制转换成IP地址
     */
    public static String num2ip(int ip) {
        int[] b = new int[4];
        String x = "";
        b[0] = (int) ((ip >> 24) & 0xff);
        b[1] = (int) ((ip >> 16) & 0xff);
        b[2] = (int) ((ip >> 8) & 0xff);
        b[3] = (int) (ip & 0xff);
        x = Integer.toString(b[0]) + "." + Integer.toString(b[1]) + "." + Integer.toString(b[2]) + "." + Integer.toString(b[3]);

        return x;
    }

    /**
     * 日期转星期
     *
     * @param datetime
     * @return
     */
    public static int dateToWeek(String datetime) {
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
        String[] weekDays = {"7", "1", "2", "3", "4", "5", "6"};
        Calendar cal = Calendar.getInstance(); // 获得一个日历
        try {
            cal.setTime(f.parse(datetime));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        int w = cal.get(Calendar.DAY_OF_WEEK) - 1; // 指示一个星期中的某天。
        if (w < 0)
            w = 0;
        return Integer.parseInt(weekDays[w]);
    }


    public static String getSign() throws UnsupportedEncodingException, NoSuchAlgorithmException {

//        List<String> requestParams = Lists.newArrayList("tag=" + tag, "params=" + params, "key=" + KEY, "token=" + TOKEN, "createTime=" + createTime);

        List<String> requestParams = new ArrayList<>();
        requestParams.add("tag=flight.national.tts.bid.price");
        requestParams.add("token=b6631d213333bfc9638398d471f0a91e");
        requestParams.add("params={\"dpt\":\"PEK\",\"arr\":\"SHA\",\"flightDate\":\"2019-01-20\",\"domain\":\"xss.trade.qunar.com\",\"carrier\":\"9C\"}");
        requestParams.add("createTime=" + System.currentTimeMillis());
        requestParams.add("key=449b43a68dc74d85c9ff48048e0b9022");
        for (String requestParam : requestParams) {
            System.err.println(requestParam);
        }
        Collections.sort(requestParams);

        for (String requestParam : requestParams) {
            System.err.println(requestParam);
        }

        String beforeMd5Str = linkStr(requestParams);
        String sign = MD5Utils.MD5Encode(beforeMd5Str, null);
        System.out.println("before md5 str:" + beforeMd5Str);
        log.info("before md5 str={}, after md5 str={}", beforeMd5Str, sign);

        System.err.println(beforeMd5Str);
        System.err.println(sign);
        return sign;
    }


    public static void main(String[] args) {
        List<String> list1 = new ArrayList<String>();
        list1.add("A");
        list1.add("B");
        list1.add("C");

        List<String> list2 = new ArrayList<String>();
        list2.add("C");
        list2.add("B");
        list2.add("D");
        // 并集
//        list1.addAll(list2);
//        System.err.println(list1);
        // 去重复并集
        list2.removeAll(list1);
        list1.addAll(list2);
        System.err.println(list1);
//        // 交集
//        list1.retainAll(list2);
//        System.err.println(list1);
//        // 差集
//        list1.removeAll(list2);
//        System.err.println(list1);
    }

    public static String linkStr(List<String> requestParams) {
        StringBuilder sb = new StringBuilder();
        for (String param : requestParams) {
            sb.append(param);
        }
        return sb.toString();
    }
}
